/*
 * @(#)WorkflowRetrievalManager.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;
import com.dcivision.framework.bean.AbstractBaseObject;
import com.dcivision.user.bean.MtmUserGroupUserRole;
import com.dcivision.user.bean.MtmUserRecordUserGroup;
import com.dcivision.user.bean.MtmUserRecordUserRole;
import com.dcivision.user.bean.UserGroup;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.bean.UserRole;
import com.dcivision.user.dao.MtmUserGroupUserRoleDAObject;
import com.dcivision.user.dao.MtmUserRecordUserGroupDAObject;
import com.dcivision.user.dao.MtmUserRecordUserRoleDAObject;
import com.dcivision.user.dao.UserGroupDAObject;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.user.dao.UserRoleDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWfProgressWfProgress;
import com.dcivision.workflow.bean.MtmWfStepFormRecord;
import com.dcivision.workflow.bean.MtmWfStepNotificationRule;
import com.dcivision.workflow.bean.MtmWfStepNotificationTarget;
import com.dcivision.workflow.bean.MtmWorkflowProgressPriorityRule;
import com.dcivision.workflow.bean.MtmWorkflowStepPriorityRule;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.MtmWorkflowStepWorkflowStep;
import com.dcivision.workflow.bean.WorkflowAction;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.bean.WorkflowStage;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.bean.WorkflowStepFormEquat;
import com.dcivision.workflow.bean.WorkflowStepParameterValue;
import com.dcivision.workflow.bean.WorkflowStepRoute;
import com.dcivision.workflow.dao.MtmWfProgressWfProgressDAObject;
import com.dcivision.workflow.dao.MtmWfStepFormRecordDAObject;
import com.dcivision.workflow.dao.MtmWfStepNotificationRuleDAObject;
import com.dcivision.workflow.dao.MtmWfStepNotificationTargetDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressUserRecordDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepPriorityRuleDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepWorkflowStepDAObject;
import com.dcivision.workflow.dao.WorkflowActionDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.dao.WorkflowStageDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;
import com.dcivision.workflow.dao.WorkflowStepFormEquatDAObject;
import com.dcivision.workflow.dao.WorkflowStepParameterValueDAObject;
import com.dcivision.workflow.dao.WorkflowStepRouteDAObject;

/**
 * WorkflowRetrievalManager.java
 *
 * This class is responsible for workflow operation.
 *
 * @author Angus Shiu
 * @company DCIVision Limited
 * @creation date 4/12/2003
 * @version $Revision: 1.78.2.2 $
 */

public class WorkflowRetrievalManager {
  
  public static final String REVISION = "$Revision: 1.78.2.2 $";
  
  protected Log log = LogFactory.getLog(this.getClass().getName());
  private SessionContainer sessionCon = null;
  private Connection dbConn = null;
  private List  workflowProgressList =new ArrayList();

  public static final String PARAMVALUE_AUTOTASK = "C";
  
  /** Indicates the parameter value is referenced to sub workflow. */
  public static final String PARAMVALUE_SUB_WORKFLOW = "S";
  
  /**
   * Constructor
   *
   * @param sessionContainer
   * @param conn
   */
  public WorkflowRetrievalManager(SessionContainer sessionContainer, Connection conn) {
    this.sessionCon = sessionContainer;
    this.dbConn = conn;
  }
  /**
   * Gets the detail workflow step information by workflow step id, and parent step group id
   *
   * @param workflowStepID The workflow step ID
   * @param groupID The parent step group ID
   * @return AbstractBaseObject storing the WorkflowStep object, you may need to
   *         explicitly cast to WorkflowStep
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   * @see com.dcivision.workflow.bean.MtmWorkflowStepWorkflowStep
   */
  public AbstractBaseObject getWorkflowStepInfo(Integer workflowStepID, Integer groupID) throws ApplicationException {
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    MtmWorkflowStepWorkflowStepDAObject stepStepDAO = new MtmWorkflowStepWorkflowStepDAObject(sessionCon, dbConn);
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionCon, dbConn);
    WorkflowStepRouteDAObject wfStepRouteDAO = new WorkflowStepRouteDAObject(sessionCon, dbConn);
    WorkflowStepFormEquatDAObject formEquatDAO = new WorkflowStepFormEquatDAObject(sessionCon, dbConn);
    WorkflowRecordDAObject wfRecordDAO = new WorkflowRecordDAObject(sessionCon, dbConn);
    
    WorkflowStep step = (WorkflowStep)stepDAO.getObjectByID(workflowStepID);
    
    String completeAckMtd = step.getOnCompleteAckMethod();
    if (completeAckMtd!=null && completeAckMtd.indexOf(WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_MAIL)>=0){
      step.setNotifyOwnerTaskArrivalByMail(WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_MAIL);
    }
    if (completeAckMtd!=null && completeAckMtd.indexOf(WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_SYSTEM)>=0) {
      step.setNotifyOwnerTaskArrivalBySystem(WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_SYSTEM);
    }
    if (completeAckMtd!=null && completeAckMtd.indexOf(WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_MAIL)>=0) {
      step.setNotifyAllTaskCompletedByMail(WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_MAIL);
    }
    if (completeAckMtd!=null && completeAckMtd.indexOf(WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_SYSTEM)>=0) {
      step.setNotifyAllTaskCompletedBySystem(WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_SYSTEM);
    }
    
    String noResponseAckMtd = step.getOnNoResponseAckMethod();
    if (noResponseAckMtd!=null && noResponseAckMtd.indexOf(WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_MAIL)>=0) {
      step.setNotifyOwnerTaskOverdueByMail(WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_MAIL);
    }
    if (noResponseAckMtd!=null && noResponseAckMtd.indexOf(WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_SYSTEM)>=0) {
      step.setNotifyOwnerTaskOverdueBySystem(WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_SYSTEM);
    }
    if (noResponseAckMtd!=null && noResponseAckMtd.indexOf(WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_MAIL)>=0) {
      step.setNotifyAllTaskOverdueByMail(WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_MAIL);
    }
    if (noResponseAckMtd!=null && noResponseAckMtd.indexOf(WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_SYSTEM)>=0) {
      step.setNotifyAllTaskOverdueBySystem(WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_SYSTEM);
    }
    
    if (!Utility.isEmpty(step.getActionID())) {
      step.setActionType(step.getActionType() + step.getActionID());
    }
    
    //* set the overdue type checkbox
    if (step.getOnNoResponseFor()!=null) {
      step.setOverDueType(WorkflowStep.OVER_DUE_TYPE_DAYS);
    } else if (step.getOnNoResponseAfter()!=null) {
      step.setOverDueType(WorkflowStep.OVER_DUE_TYPE_DATE);
    } else if (GlobalConstant.TRUE.equals(step.getAllowAssignDueDate()) ){
      step.setOverDueType(WorkflowStep.OVER_DUE_TYPE_ALLOW_ASSIGN);  
    } else {
      step.setOverDueType(WorkflowStep.OVER_DUE_TYPE_NA);
    }
    
    //* get ParentStepID(s) under the group
    List parentStepsList = new ArrayList();
    if (groupID!=null) {
      parentStepsList = stepStepDAO.getListByWorkflowRecordIDGroupIDAndChildID(step.getWorkflowRecordID(), groupID, workflowStepID);
    }
    log.debug("parent step list: "+parentStepsList.size());
    String[] parentStepIDs = new String[parentStepsList.size()];
    for (int i=0; i<parentStepsList.size(); i++) {
      MtmWorkflowStepWorkflowStep mtmStepStep = (MtmWorkflowStepWorkflowStep) parentStepsList.get(i);
      parentStepIDs[i] = mtmStepStep.getParentType() + "-" + mtmStepStep.getParentStepID(); //* the value of check box is in [parentType] + [parentStepID]
    }
    step.setParentStepIDs(parentStepIDs);
    
    //* get step user actor
    List userRecordList = new ArrayList(), userGroupList = new ArrayList(), userRoleList = new ArrayList();
    List userActorList = stepActorDAO.getListByWorkflowStepID(workflowStepID);
    List actorTypeList = new ArrayList();
    log.debug("step user actor list: "+userActorList.size());
    for (int i=0; i<userActorList.size(); i++) {
      MtmWorkflowStepUserActor stepActor = (MtmWorkflowStepUserActor) userActorList.get(i);
      log.debug("current actor type: " + stepActor.getActorType());
      if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(stepActor.getActorType()) ) { //* current actor is a user account
        userRecordList.add(stepActor.getActorID().toString() + "_" + stepActor.getPermission());
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(stepActor.getActorType()) ) { //* current actor is an user group
        userGroupList.add(stepActor.getActorID().toString() + "_" + stepActor.getPermission());
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(stepActor.getActorType()) ) { //* current actor is an user role
        userRoleList.add(stepActor.getActorID().toString() + "_" + stepActor.getPermission());
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_RECURSIVE_RUNTIME_ASSIGN.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(stepActor.getActorType())                                 
          || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(stepActor.getActorType())
          || MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(stepActor.getActorType()) 
          || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(stepActor.getActorType())                                 
      )  {//* current actor is special actor type
        log.debug("special actor type found!!!!!!!!!!");
        if( MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(stepActor.getActorType()) 
            || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(stepActor.getActorType()) ){
          actorTypeList.add(stepActor.getActorType() + stepActor.getActorID() + "_" + stepActor.getPermission());
        } else {
          actorTypeList.add(stepActor.getActorType() + "_" + stepActor.getPermission());         
        } 
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(stepActor.getActorType()) ) {
        step.setAssignActorType(stepActor.getActorType()); 
        actorTypeList.add(stepActor.getActorType()+"_"+stepActor.getPermission());
      }
    }
    
    String[] userRecords = new String[0], userRoles = new String[0], userGroups = new String[0], actorTypes = new String[0];
    userRecords = (String[]) userRecordList.toArray(userRecords);
    userRoles = (String[]) userRoleList.toArray(userRoles);
    userGroups = (String[]) userGroupList.toArray(userGroups);
    actorTypes = (String[]) actorTypeList.toArray(actorTypes);
    
    step.setUserRecords(userRecords);
    step.setUserRoles(userRoles);
    step.setUserGroups(userGroups);
    step.setActorTypes(actorTypes);
    
    //get the route name from Workflow_Step_Route table
    if(WorkflowStep.ACTION_TYPE_USER_DEFINED_TASK.equals(step.getActionType())){
      List routeList = wfStepRouteDAO.getListByWorkflowStepID(step.getID());
      String routeName = "";
      for(int j=0; !Utility.isEmpty(routeList) && j<routeList.size(); j++){
        WorkflowStepRoute route = (WorkflowStepRoute)routeList.get(j);
        routeName += route.getRouteName() + "|";
      }
      step.setRouteListValue(routeName);
    }
    
    
    //get the current step's parent type from Mtm_WF_Step_WF_Step table
    List tmpWfStep2List = stepStepDAO.getListByParentStepID(workflowStepID);
    for(int k=0; k<tmpWfStep2List.size(); k++){
      MtmWorkflowStepWorkflowStep mtmWfStep2 = (MtmWorkflowStepWorkflowStep)tmpWfStep2List.get(k);
      step.setCurrentType(mtmWfStep2.getParentType());
      step.setLoopBackALLOffset(mtmWfStep2.getLoopBackAllBranch());
      break;
    }
    
    //get the form equation from Workflow_Step_Form_Equat
    if(WorkflowStep.ACTION_TYPE_FORM_DRIVEN.equals(step.getActionType())){    
      List formEquatList = formEquatDAO.getListByWorkflowStepID(step.getID());
      log.debug("formEquatList.size():"+formEquatList.size());
      String formEquatListValue = "";
      for(int i=0; i<formEquatList.size(); i++){
        WorkflowStepFormEquat formEquat = (WorkflowStepFormEquat)formEquatList.get(i);
        String tempEquat = "";
        tempEquat = 
          formEquat.getRouteName() + ";" +
          formEquat.getDefaultFlag() + ";" +
          formEquat.getOperand1() + ";" +
          formEquat.getOperand2() + ";" +
          formEquat.getCompare() + ";" +
          formEquat.getFormEquation() + ";" +
          formEquat.getOperationType() + ";" +
          formEquat.getDateFormat();
        
        if(!Utility.isEmpty(formEquatListValue)){
          formEquatListValue += "$$" + tempEquat;
        } else {
          formEquatListValue = tempEquat;   
        }        
      }
      step.setFormEquationListValue(formEquatListValue);
      log.debug("formEquatListValue:"+formEquatListValue);
    }
    
    
    // get have existed notification rules for this step
    step.setNotificationRuleListValue(this.getWorkflowStepNotificationRuleByStepID(step.getID()));
    
    //get the priority rules for the priority    
    step.setPriorityRuleListValue(this.getWorkflowStepPriorityRuleByStepID(step.getID()) );  
    
    //get the workflow record released status
    WorkflowRecord wfRecord = (WorkflowRecord)wfRecordDAO.getObjectByID(step.getWorkflowRecordID());
    step.setReleased(WorkflowRecord.WORKFLOW_RECORD_RELEASE.equals(wfRecord.getStatus()) );
    
    //get the bind form item value
    step.setBindFormItemValue(this.getBindFormItemValue(step.getID()) );
    
    //get workflow stage ID
    step.setWorkflowStageID(this.getWorkflowStageByWorkflowStepID(step.getID()));
    return step;
  }
  /**
   * Gets a list of child step of the given parent step ID
   *
   * @param parentID The parent step ID
   * @return List of WorkflowStep object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getChildWorkflowStepListByParentID(Integer parentID) throws ApplicationException {
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    return stepDAO.getListByParentStepID(parentID);
  }
  
  /**
   * Gets a list of workflow step of the given workflow record id
   *
   * @param workflowRecordID The workflow record ID
   * @return  List of WorkflowStep object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowRecord
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getWorkflowStepListByRecordID(Integer workflowRecordID) throws ApplicationException {
    return this.getWorkflowStepListByRecordIDAndExcludeStep(workflowRecordID, null);
  }
  
  /**
   * Gets a list of workflow step under the workflow record id, excluding the step specified
   *
   * @param workflowRecordID The workflow record ID
   * @param excludeStepID The step ID to be excluded
   * @return  List of WorkflowStep object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowRecord
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getWorkflowStepListByRecordIDAndExcludeStep(Integer workflowRecordID, Integer excludeStepID) throws ApplicationException {
    List stepList = new ArrayList();
    List childStepList = new ArrayList();
    if (excludeStepID!=null) {
      stepList.add(excludeStepID);
      
      
      // TODO get current step is child steps, set child steps id to stepList[];
      //childStepList = this.getChildStepList(excludeStepID, childStepList);
      //log.debug("The child steps number is::::::" + childStepList.size());
      //for (int i = 0; i < childStepList.size(); i++) {
      //WorkflowStep childStep = (WorkflowStep)childStepList.get(i);
      //stepList.add(childStep.getID());
      //  log.debug("the current child step id is:::::::" + childStep.getID().toString());
      //  }
      
    }
    return this.getWorkflowStepListByRecordIDAndExcludeStepList(workflowRecordID, stepList);
  }
  
  /**
   * Gets a list of workflow step of the given workflow record id, excluding the list of steps ID specified
   *
   * @param workflowRecordID The workflow record ID
   * @param excludeStepIDs List of step ID to be excluded
   * @return  List of WorkflowStep object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowRecord
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getWorkflowStepListByRecordIDAndExcludeStepList(Integer workflowRecordID, List excludeStepIDs) throws ApplicationException {
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    return stepDAO.getListByWorkflowRecordIDAndExcludeSteps(workflowRecordID, excludeStepIDs);
  }
  /**
   * Gets a list of users related to this workflow track, which includes pre-assigned
   * step owners, dynamically assign step owners, and action takers.
   *
   * @param trackID The workflow track ID
   * @return List of MtmWorkflowProgressUserRecord object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   * @see com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord
   * @deprecated
   */
  public List getWorkflowProgressUserRecordListByTrackID(Integer trackID) throws ApplicationException {
    List result = new ArrayList();
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionCon, dbConn);
    MtmWorkflowProgressUserRecordDAObject progressUserDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, dbConn);
    
    List progressList = progressDAO.getListByTrackID(trackID);
    for (int i=0; i<progressList.size(); i++) { 
      WorkflowProgress progress = (WorkflowProgress) progressList.get(i);
      List progressUserList = progressUserDAO.getListByWorkflowProgressID(progress.getID());
      result.addAll(progressUserList);
    }
    
    return result;
  }
  /**
   * Gets an automatic task definition by workflow action ID
   *
   * @param workflowActionID The workflow action ID
   * @return WorkflowAction object (the automatic task definition)
   * @throws ApplicationException
   */
  public WorkflowAction getWorkflowActionByActionID(Integer workflowActionID) throws ApplicationException {
    WorkflowActionDAObject actionDAO = new WorkflowActionDAObject(sessionCon, dbConn);
    return ((WorkflowAction)actionDAO.getObjectByID(workflowActionID));
  }
  
  /**
   * Gets an instance of the Workflow Processor subclass based on the name given.
   *
   * @param workflowProcessorClassName      the name of the Worfklow Processor subclass
   * @return                                instance of the named subclass
   * @throws ApplicationException
   */
  public WorkflowProcessor getWorkflowProcessor(String workflowProcessorClassName) throws ApplicationException {
    WorkflowProcessor processor = null;
    try {
      processor = (WorkflowProcessor) Class.forName(workflowProcessorClassName).newInstance();
    } catch (Exception e) {
      throw new ApplicationException(WorkflowErrorConstant.WORKLFOW_PROCESSOR_CLASS_NOT_FOUND);
    }
    return processor;
  }
  /**
   * Gets the next step sequence number of the given workflow record ID
   *
   * @param workflowRecordID The workflow record ID
   * @return The next sequence number
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowRecord
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public synchronized Integer getNextStepSeqNumber(Integer workflowRecordID) throws ApplicationException {
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    return (stepDAO.getNextStepSeqNumber(workflowRecordID));
  }
  /**
   * Gets a list of UserRecord that is pre-assigned as user/group/role owners of the workflow step of given ID.
   * (Dynamically assigned are not included)
   *
   * @param workflowStepID The workflow step ID
   * @return List of UserRecord
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   * @see com.dcivision.user.bean.UserRecord
   */
  public synchronized List getUserListForStepAssignment(Integer workflowStepID) throws ApplicationException {
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, dbConn);    
    List userRecordList = new ArrayList();
    List userRecordIDList = new ArrayList();
    
    userRecordIDList = this.getUserRecordIDListForStepAssignment(workflowStepID);
    
    //get the userRecordList
    for(int n=0; n<userRecordIDList.size(); n++){
      UserRecord userRecord = (UserRecord)userDAO.getObjectByID(new Integer(userRecordIDList.get(n).toString()));
      if(userRecordList.indexOf(userRecord) < 0){
        userRecordList.add(userRecord);
      }
    }
    
    if(!Utility.isEmpty(userRecordList)){
      return userRecordList;  
    }
    
    return (userDAO.getFullList());
  }
  /**
   * Gets a list of pending progress(task) by a specific track ID
   *
   * @param trackID The workflow track ID
   * @return List of WorkflowProgress object which is in pending state
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public List getPendingProgressListByTrackID(Integer trackID) throws ApplicationException {
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionCon, dbConn);
    return (progressDAO.getPendingProgressListByTrackID(trackID));
  }
  
  
  /**
   * Gets a list of non-automatic parent progress
   * <pre>
   *    1
   *   / \
   *  2   3
   *  \   4(automatic task), 2 and 4 merge to 5, get the non auto parent of 5 which is 2,3
   *   \ /
   *    5
   * </pre>
   * @param trackID the track id of the workflow progress
   * @param workStepID the step no. of the current workflow progress
   * @return List of the non automatic parent progress
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public List getNonSystemParent(Integer trackID, Integer workStepID) throws ApplicationException{
    
    MtmWorkflowStepWorkflowStepDAObject mtmWorkflowStepDAO = new MtmWorkflowStepWorkflowStepDAObject(sessionCon,dbConn);
    WorkflowStepDAObject wfStepDAO = new WorkflowStepDAObject(sessionCon,dbConn);
    WorkflowProgressDAObject workflowProgressDAO = new WorkflowProgressDAObject(sessionCon,dbConn);
    
    List parentStepList = mtmWorkflowStepDAO.getListByChildStepID(workStepID);
    //vector store same parent level's parent
    Vector parentMtmWorkflow = new Vector();
    boolean isSysAutoStep = true;
    boolean isHead = false;
    List parentStepInstanceList = new ArrayList();
    
    
    for(int i=0;i<parentStepList.size();i++){ 
      MtmWorkflowStepWorkflowStep mtmWorkflowStepWorkflowStep = (MtmWorkflowStepWorkflowStep)parentStepList.get(i);
      
      WorkflowStep workflowStep =(WorkflowStep)wfStepDAO.getObjectByID(mtmWorkflowStepWorkflowStep.getParentStepID())	;
      
      //check is it a automatic task
      if(!WorkflowStep.ACTION_TYPE_SYSTEM_AUTO.equals(workflowStep.getActionType())){
        isSysAutoStep = false;	 
        parentStepInstanceList.addAll(workflowProgressDAO.getListByStepIDAndTrackID(workflowStep.getID(),trackID));
      }else{
        //if it is automatic task, record and then used for find parent
        parentMtmWorkflow.add(mtmWorkflowStepWorkflowStep);
      }
      
    }//end for
    //if found non auto parent step the return, otherwise do recursively to the grandparent
    //if ((parentStepInstanceList.size()==0)&&(parentStepList.size()>0)){
    if(parentMtmWorkflow.size()>0){
      
      for(int j=0;j<parentMtmWorkflow.size();j++){
        MtmWorkflowStepWorkflowStep mtmWorkflowStepWorkflowStep = (MtmWorkflowStepWorkflowStep)parentMtmWorkflow.get(j);
        parentStepInstanceList.addAll(this.getNonSystemParent(trackID,mtmWorkflowStepWorkflowStep.getParentStepID()));
      }
      
    }
    
    return parentStepInstanceList;
    
  }
  /**
   * Gets a list of MtmWorkflowProgressUserRecord object related to this progress
   *
   * @param progressID The current progress ID
   * @return List of MtmWorkflowProgressUserRecord object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   * @see com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord
   */
  public List getWorkflowProgressUserRecordListByProgressID(Integer progressID) throws ApplicationException {
    
    MtmWorkflowProgressUserRecordDAObject progressUserDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, dbConn);
    List progressUserList = progressUserDAO.getListByWorkflowProgressID(progressID);
    
    
    return progressUserList;
  }
  
  
  
  /**
   * Gets the step name of a workflow progress
   *
   * @param wkflowProgressID The workflow progress ID
   * @return The step name
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public String getStepNameByWkProgressID(Integer wkflowProgressID) throws ApplicationException {
    WorkflowProgressDAObject workflowProgressDAO = new WorkflowProgressDAObject(sessionCon,dbConn);
    return workflowProgressDAO.getStepNameByWkFlowProgressID(wkflowProgressID) ;
  }
  
  /**
   * Gets a List of UserRecord that can be dynamically assigned for a task
   *
   * @param workflowStepID The workflow step of the task
   * @return List of UserRecord for dynamic assign
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   */
  public synchronized List getUserRecordListForStepAssignment(List mtmActorList,Integer workflowStepID) throws ApplicationException {
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, dbConn);

    
    List userRecordList = new ArrayList();
    List userRecordIDList = new ArrayList();
    
    //get the userRecordID according to this actor type
    for(int i=0; i<mtmActorList.size(); i++){
      MtmWorkflowStepUserActor tmpWfStepUserActor = (MtmWorkflowStepUserActor)mtmActorList.get(i);
      if(MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(tmpWfStepUserActor.getActorType()) ){
        userRecordIDList.add(tmpWfStepUserActor.getActorID());
      } 
    }
    
    //get the userRecordList
    for(int n=0; n<userRecordIDList.size(); n++){
      UserRecord userRecord = (UserRecord)userDAO.getObjectByID(new Integer(userRecordIDList.get(n).toString()));
      if(userRecordList.indexOf(userRecord) < 0){
        userRecordList.add(userRecord);
      }
    }
    
    //    if(!Utility.isEmpty(userRecordList)){
    //      return userRecordList;  
    //    }
    
    return userRecordList;
  }
  
  
  /**
   * Gets a List of UserGroup that can be dynamically assigned for a task
   *
   * @param workflowStepID The workflow step of the task
   * @return List of UserGroup for dynamic assign
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserGroup
   */
  public synchronized List getUserGroupListForStepAssignment(List mtmActorList,Integer workflowStepID) throws ApplicationException {
    UserGroupDAObject userGroupDAO = new UserGroupDAObject(sessionCon, dbConn);
    
    List userGroupList = new ArrayList();
    List userGroupIDList = new ArrayList();
    
    //get the userRecordID, userGroupID or userRoleID according to this actor type
    for(int i=0; i<mtmActorList.size(); i++){
      MtmWorkflowStepUserActor tmpWfStepUserActor = (MtmWorkflowStepUserActor)mtmActorList.get(i);
      if(MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(tmpWfStepUserActor.getActorType()) ){
        userGroupIDList.add(tmpWfStepUserActor.getActorID());
      } 
    }
    
    //get the userGroupList
    for(int n=0; n<userGroupIDList.size(); n++){
      UserGroup userGroup = (UserGroup)userGroupDAO.getObjectByID((Integer)userGroupIDList.get(n));
      if(userGroupList.indexOf(userGroup) < 0){
        userGroupList.add(userGroup);
      }
    }
    
    //    if(!Utility.isEmpty(userGroupList)){
    //      return userGroupList;  
    //    }
    
    return userGroupList;
  }
  
  /**
   * Gets a List of UserRole that can be dynamically assigned for a task
   *
   * @param workflowStepID The workflow step of the task
   * @return List of UserRole for dynamic assign
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRole
   */
  public synchronized List getUserRoleListForStepAssignment(List mtmActorList, Integer workflowStepID) throws ApplicationException {
    UserRoleDAObject userRoleDAO = new UserRoleDAObject(sessionCon, dbConn);
    
    List userRoleList = new ArrayList();
    List userRoleIDList = new ArrayList();
    
    //get the userRecordID, userGroupID or userRoleID according to this actor type
    for(int i=0; i<mtmActorList.size(); i++){
      MtmWorkflowStepUserActor tmpWfStepUserActor = (MtmWorkflowStepUserActor)mtmActorList.get(i);
      if((MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(tmpWfStepUserActor.getActorType())) ){
        userRoleIDList.add(tmpWfStepUserActor.getActorID());
      }
    }
    
    //get the userRecordList
    for(int n=0; n<userRoleIDList.size(); n++){
      UserRole userRole = (UserRole)userRoleDAO.getObjectByID((Integer)userRoleIDList.get(n));
      if(userRoleList.indexOf(userRole) < 0){
        userRoleList.add(userRole);
      }
    }
    
    //    if(!Utility.isEmpty(userRoleList)){
    //      return userRoleList;  
    //    }
    
    return userRoleList;
  }
  
  /**
   * Gets a List of String Array storing the special actor type that can be
   * dynamically assigned for a task. For example, for workflow submitter, the
   * following List of two dimensional array will be returned.
   * ACTOR_TYPE_MAP[0][0] = "Workflow Submitter";<br>
   * ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER;<br>
   *
   * @param workflowStepID The workflow step of the task
   * @return List of two dimensional array storing the actor type label and type.
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public synchronized List getSpecialActorTypeListForStepAssignment(Integer workflowStepID) throws ApplicationException {
    UserRoleDAObject userRoleDAO = new UserRoleDAObject(sessionCon, dbConn);
    MtmWorkflowStepUserActorDAObject mtmWfStepUserActorDAO = new MtmWorkflowStepUserActorDAObject(sessionCon, dbConn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    
    List actorTypeList = new ArrayList();
    
    Locale locale = sessionCon.getSessionLocale();
    List mtmUserActorList = mtmWfStepUserActorDAO.getListByWorkflowStepID(workflowStepID);
    
    for(int i=0; i<mtmUserActorList.size(); i++){
      MtmWorkflowStepUserActor tmpWfStepUserActor = (MtmWorkflowStepUserActor)mtmUserActorList.get(i);
      String[][] ACTOR_TYPE_MAP = new String[1][2];
      if(MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(tmpWfStepUserActor.getActorType()) ){
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.submitter");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(tmpWfStepUserActor.getActorType()) ){
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.everyone");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(tmpWfStepUserActor.getActorType()) ){      
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.report_to");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER.equals(tmpWfStepUserActor.getActorType()) ){
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.previous_task_owner");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(tmpWfStepUserActor.getActorType()) ){
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.previous_task_action_taker");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(tmpWfStepUserActor.getActorType()) ){
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(locale, "workflow.label.report_to_of_previous_task");
        ACTOR_TYPE_MAP[0][1] = MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER;
        
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(tmpWfStepUserActor.getActorType()) ){
        WorkflowStep step = (WorkflowStep)stepDAO.getObjectByID(tmpWfStepUserActor.getActorID() );
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.n_step_action_taker", step.getStepSeq() + ". " + step.getStepName());        
        ACTOR_TYPE_MAP[0][1] = tmpWfStepUserActor.getActorType() + tmpWfStepUserActor.getActorID();
        
      } else if( MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(tmpWfStepUserActor.getActorType()) ){
        WorkflowStep step = (WorkflowStep)stepDAO.getObjectByID(tmpWfStepUserActor.getActorID() );
        ACTOR_TYPE_MAP[0][0] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.step_n_action_taker_report_to", step.getStepSeq() + ". " + step.getStepName());
        ACTOR_TYPE_MAP[0][1] = tmpWfStepUserActor.getActorType() + tmpWfStepUserActor.getActorID();    
      } else {
        ACTOR_TYPE_MAP = null;
      }
      if(!Utility.isEmpty(ACTOR_TYPE_MAP) && ACTOR_TYPE_MAP.length > 0 ){
        actorTypeList.add(ACTOR_TYPE_MAP);
      }
    }
    
    return actorTypeList;
  }
  
  /**
   * Gets all the priority rules for this workflow step. The rules will be returned
   * in a "|" seperated String. Each rule will be in the following format<br>
   * escalateAmount,escalateField,escalateTrigger,escalateLevel,notifyEmail,notifySystem<br>
   * So, a string of "5,5,A,1,null,S|1,5,B,2,E,S" actually means 2 priority escalation
   * rules, the first one is,<br>
   * Escalate 1 level after task arrived for 5 days, system notification only<br>
   * and the second is,<br>
   * Escalate 2 level when it is 1 days before the due date, email and system notification
   *
   * @param workflowStepID The workflow step ID
   * @return String representing all the priority rules, "|" separated.
   * @throws ApplicationException
   * @see java.util.Calendar#DATE
   * @see java.util.Calendar#HOUR
   * @see java.util.Calendar#MINUTE
   * @see com.dcivision.workflow.bean.MtmWorkflowProgressPriorityRule
   */
  private String getWorkflowStepPriorityRuleByStepID(Integer workflowStepID)throws ApplicationException {
    MtmWorkflowStepPriorityRuleDAObject ruleDAO = new MtmWorkflowStepPriorityRuleDAObject(sessionCon, dbConn);
    String priorityRuleListValue = "";
    List priorityRuleList = ruleDAO.getListByWorkflowStepID(workflowStepID);
    
    for(int i=0; i<priorityRuleList.size(); i++){
      MtmWorkflowStepPriorityRule priorityRule = (MtmWorkflowStepPriorityRule)priorityRuleList.get(i);
      String tmpRule = "";
      String ackMethod = "";
      
      if(priorityRule.getEscalateAckMethod().indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_EMAIL) >-1){
        ackMethod = MtmWorkflowProgressPriorityRule.NOTIFY_BY_EMAIL;
      } else{
        ackMethod = "null";  
      }
      
      if(priorityRule.getEscalateAckMethod().indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_SYSTEM) >-1){
        ackMethod += "," + MtmWorkflowProgressPriorityRule.NOTIFY_BY_SYSTEM;
      } else{
        ackMethod += "," + "null";  
      }
      
      tmpRule = priorityRule.getEscalateAtAmt() + "," +
      priorityRule.getEscalateAtField() + "," +
      priorityRule.getEscalateTrigger() + "," +         
      priorityRule.getEscalateLevel() + "," + 
      ackMethod;
      if(i==0){
        priorityRuleListValue = tmpRule;
      } else {
        priorityRuleListValue += "|" + tmpRule; 
      }
    } 
    return priorityRuleListValue;
  }
  /**
   * Gets all the notification rules for this workflow step. The rules will be returned
   * in a "|" seperated String. Each rule will be in the following format<br>
   * notifyTrigger,notifyAmount,notifyField,notifyEmail,notifySystem,targetID$targetName$targetType:[targetID$targetName$targetType]<br>
   * So, a string of "C,0,12,E,S,389$3. 3&#39;s Owner$O|A,1,5,E,S,3$Role 3$R:0$Workflow Submitter$S"
   * actually means 2 notification rules, the first one is,<br>
   * Notify the owners of step "3. 3" (with ID=389) by email and system after the task is completed for 0 minutes.<br>
   * and the second is,<br>
   * Notify all "Role 3" users and "Workflow Submitter" by email and system after the task is arrived for 1 days.
   *
   * @param workflowStepID The workflow step ID
   * @return String representing all the notification rules, "|" separated.
   * @throws ApplicationException
   * @see java.util.Calendar#DATE
   * @see java.util.Calendar#HOUR
   * @see java.util.Calendar#MINUTE
   * @see com.dcivision.workflow.bean.MtmWfStepNotificationRule
   * @see com.dcivision.workflow.bean.MtmWfStepNotificationTarget
   */
  private String getWorkflowStepNotificationRuleByStepID(Integer workflowStepID)throws ApplicationException {
    MtmWfStepNotificationRuleDAObject notificationRuleDAO = new MtmWfStepNotificationRuleDAObject(sessionCon, dbConn);
    MtmWfStepNotificationTargetDAObject notificationTargetDAO = new MtmWfStepNotificationTargetDAObject(sessionCon, dbConn);
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, dbConn);
    UserGroupDAObject groupDAO = new UserGroupDAObject(sessionCon, dbConn);
    UserRoleDAObject roleDAO = new UserRoleDAObject(sessionCon, dbConn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    WorkflowStepDAObject workflowStepDAO = new WorkflowStepDAObject(sessionCon, dbConn);
    String notificationRuleListValue = "";
    List notificationRuleList = notificationRuleDAO.getListByWorkflowStepID(workflowStepID);
    Locale locale = sessionCon.getSessionLocale();
    
    for (int i=0; i < notificationRuleList.size(); i++) {
      MtmWfStepNotificationRule  notificationRule = (MtmWfStepNotificationRule)notificationRuleList.get(i);
      String tmpRule = "";
      String ackMethod = "";
      
      if(notificationRule.getNotifyAckMethod().indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_EMAIL) >-1){
        ackMethod = MtmWorkflowProgressPriorityRule.NOTIFY_BY_EMAIL;
      } else{
        ackMethod = "null";  
      }
      
      if(notificationRule.getNotifyAckMethod().indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_SYSTEM) >-1){
        ackMethod += "," + MtmWorkflowProgressPriorityRule.NOTIFY_BY_SYSTEM;
      } else{
        ackMethod += "," + "null";  
      }
      
      tmpRule = notificationRule.getNotifyTrigger() + "," +
      notificationRule.getNotifyAtAmt() + "," +
      notificationRule.getNotifyAtField() + "," +         
      ackMethod;
      List currentTargetList = notificationTargetDAO.getListByNotifyRuleID(notificationRule.getID());
      
      String currentOwners = "";
      if (!Utility.isEmpty(currentTargetList)) {
        for (int h = 0; h < currentTargetList.size(); h++) {
          MtmWfStepNotificationTarget currentTarget = (MtmWfStepNotificationTarget)currentTargetList.get(h);
          String currentOwner = "";
          if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(currentTarget.getTargetType())) {
            UserRecord userRecord = (UserRecord)userDAO.getObjectByID(currentTarget.getTargetID());
            currentOwner += currentTarget.getTargetID().toString() + "$" + userRecord.getFullName() +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(currentTarget.getTargetType())) {
            UserGroup userGroup = (UserGroup)groupDAO.getObjectByID(currentTarget.getTargetID());
            currentOwner += currentTarget.getTargetID().toString() + "$" + userGroup.getGroupName() +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(currentTarget.getTargetType())) {
            UserRole userRole = (UserRole)roleDAO.getObjectByID(currentTarget.getTargetID());
            currentOwner += currentTarget.getTargetID().toString() + "$" + userRole.getRoleName() +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(currentTarget.getTargetType())) {
            currentOwner += currentTarget.getTargetID().toString() + "$" + MessageResourcesFactory.getMessage(locale, "workflow.label.submitter") +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_EVERYONE.equals(currentTarget.getTargetType())) {
            currentOwner += currentTarget.getTargetID().toString() + "$" + MessageResourcesFactory.getMessage(locale, "workflow.label.everyone") +"$" + currentTarget.getTargetType();
            
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(currentTarget.getTargetType())) {
            currentOwner += currentTarget.getTargetID().toString() + "$" + MessageResourcesFactory.getMessage(locale, "workflow.label.report_to") +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER.equals(currentTarget.getTargetType())) {
            currentOwner += currentTarget.getTargetID().toString() + "$" + MessageResourcesFactory.getMessage(locale, "workflow.label.previous_task_owner") +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(currentTarget.getTargetType())) {
            currentOwner += currentTarget.getTargetID().toString() + "$" + MessageResourcesFactory.getMessage(locale, "workflow.label.previous_task_action_taker") +"$" + currentTarget.getTargetType();
          } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(currentTarget.getTargetType()) || MtmWfStepNotificationTarget.TARGET_TYPE_OWNER.equals(currentTarget.getTargetType())) {
            WorkflowStep workflowStep = (WorkflowStep) stepDAO.getObjectByID(currentTarget.getTargetID());
            if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(currentTarget.getTargetType())) {
              currentOwner += currentTarget.getTargetID().toString() + "$" +MessageResourcesFactory.getMessage(locale, "workflow.label.n_step_action_taker", workflowStep.getStepSeq() + ". " + workflowStep.getStepName()) +"$" + currentTarget.getTargetType();
            } else {
              currentOwner += currentTarget.getTargetID().toString() + "$" +MessageResourcesFactory.getMessage(locale, "workflow.label.n_step_owner", workflowStep.getStepSeq() + ". " + workflowStep.getStepName()) +"$" + currentTarget.getTargetType();
            }
          } 
          // WorkflowStep currentStep = (WorkflowStep)workflowStepDAO.getObjectByID(currentTarget.getTargetID()); 
          if (Utility.isEmpty(currentOwners)) {
            currentOwners += currentOwner; 
          } else {
            currentOwners += ":" + currentOwner; 
          }
        }
        tmpRule += "," + currentOwners;
      }
      if(i==0){
        notificationRuleListValue = tmpRule;
      } else {
        notificationRuleListValue += "|" + tmpRule; 
      }
    } 
    return notificationRuleListValue;
  }
  /**
   * Gets a list of UserRecord ID that is pre-assigned as user/group/role owners of the workflow step of given ID.
   * (Dynamically assigned are not included)
   *
   * @param workflowStepID The workflow step ID
   * @return List of user record ID
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public synchronized List getUserRecordIDListForStepAssignment(Integer workflowStepID) throws ApplicationException {
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, dbConn);
    MtmWorkflowStepUserActorDAObject mtmWfStepUserActorDAO = new MtmWorkflowStepUserActorDAObject(sessionCon, dbConn);
    MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionCon, dbConn);
    MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionCon, dbConn);
    MtmUserGroupUserRoleDAObject mtmUserGroupUserRoleDAO = new MtmUserGroupUserRoleDAObject(sessionCon, dbConn);
    
    List userRecordList = new ArrayList();
    List userRecordIDList = new ArrayList();
    List userGroupIDList = new ArrayList();
    List userRoleIDList = new ArrayList();
    List mtmUserActorList = mtmWfStepUserActorDAO.getListByWorkflowStepID(workflowStepID);
    
    //get the userRecordID, userGroupID or userRoleID according to this actor type
    for(int i=0; i<mtmUserActorList.size(); i++){
      MtmWorkflowStepUserActor tmpWfStepUserActor = (MtmWorkflowStepUserActor)mtmUserActorList.get(i);
      if(MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(tmpWfStepUserActor.getActorType()) ){
        userRecordIDList.add(tmpWfStepUserActor.getActorID());
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(tmpWfStepUserActor.getActorType()) ){
        userGroupIDList.add(tmpWfStepUserActor.getActorID());
      } else if(MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(tmpWfStepUserActor.getActorType()) ){
        userRoleIDList.add(tmpWfStepUserActor.getActorID());
      }
    }
    
    //get the userRecordID belong to userGroupID
    if(!Utility.isEmpty(userGroupIDList)){
      List tmpMtmUserGroupList =  mtmUserRecordUserGroupDAO.getListByUserGroupAry(userGroupIDList);
      for(int j=0; j<tmpMtmUserGroupList.size(); j++){
        MtmUserRecordUserGroup mtmUserGroup = (MtmUserRecordUserGroup)tmpMtmUserGroupList.get(j);
        if(userRecordIDList.indexOf(mtmUserGroup.getUserRecordID()) <0 ){
          userRecordIDList.add(mtmUserGroup.getUserRecordID());
        }
      }
    }
    
    //get the userRecordID belong to userRoleID
    if(!Utility.isEmpty(userRoleIDList)){
      //get user record ID from Mtm_User_Record_User_Role table
      List tmpMtmUserRoleList =  mtmUserRecordUserRoleDAO.getListByUserRoleAry(userRoleIDList);
      for(int k=0; k<tmpMtmUserRoleList.size(); k++){
        MtmUserRecordUserRole mtmUserRole = (MtmUserRecordUserRole)tmpMtmUserRoleList.get(k);
        if(userRecordIDList.indexOf(mtmUserRole.getUserRecordID()) < 0 ){
          userRecordIDList.add(mtmUserRole.getUserRecordID());   
        }        
      }
      //get groupID from Mtm_User_Group_User_Role table
      List mtmUserGroupUserRoleList = mtmUserGroupUserRoleDAO.getListByUserRoleAry(userRoleIDList);
      List groupIDList = new ArrayList();
      Iterator it = mtmUserGroupUserRoleList.iterator();
      while(it.hasNext()){
        MtmUserGroupUserRole mtmUserGroupUserRole = (MtmUserGroupUserRole)it.next();
        groupIDList.add(mtmUserGroupUserRole.getUserGroupID());
      }
      //get user record ID from Mtm_User_Record_User_Group table
      if(!Utility.isEmpty(groupIDList)){
        List tmpUserIDList = mtmUserRecordUserGroupDAO.getUserIDListByUserGroupIDList(groupIDList);
        Iterator tmpIt = tmpUserIDList.iterator();
        while(tmpIt.hasNext()){
          Integer tmpUserID = (Integer)tmpIt.next();
          if(userRecordIDList.indexOf(tmpUserID) <0 ){
            userRecordIDList.add(tmpUserID);  
          } 
        }
      }
    }
    
    return userRecordIDList;
  }
  /**
   * Gets a list of parent (and its parents) step recursively, excludes all the automatic task
   *
   * @param stepID The workflow step id
   * @param superStepList List of parent step, initially empty list (new ArrayList)
   * @return List of all the non-auto parent step
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getSuperStepList(Integer stepID, List superStepList) throws ApplicationException {
    return getSuperStepList(stepID, superStepList, false);
  }

  /**
   * Gets a list of parent (and its parents) step recursively, excludes all the automatic task
   * @param stepID The workflow step id
   * @param superStepList List of parent step, initially empty list (new ArrayList)
   * @param includeAutoTask Include automatic task
   * @return List of all the non-auto parent step
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getSuperStepList(Integer stepID, List superStepList, boolean includeAutoTask) throws ApplicationException {
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.sessionCon, this.dbConn);
    MtmWorkflowStepWorkflowStepDAObject stepStepDAO = new MtmWorkflowStepWorkflowStepDAObject(sessionCon, dbConn);
    try {
      List tempstepList = stepStepDAO.getListByChildStepID(stepID);
      for(int i=0;i<tempstepList.size();i++){
        MtmWorkflowStepWorkflowStep mtmStepStep = (MtmWorkflowStepWorkflowStep)tempstepList.get(i);
        if (!GlobalConstant.TRUE.equals(mtmStepStep.getLoopBack())) {
          WorkflowStep currentStep = (WorkflowStep)stepDAO.getObjectByID(mtmStepStep.getParentStepID());
          //        selected step can not auto task,
          if (superStepList.indexOf(currentStep) > -1) {
            log.debug("Step " + currentStep.getStepSeq() + ". " + currentStep.getStepName() + " already in parentList");
            continue;
          }else if ( (!WorkflowStep.ACTION_TYPE_SYSTEM_AUTO.equals(currentStep.getActionType()) && Utility.isEmpty(currentStep.getActionID())) || includeAutoTask) {
            superStepList.add(currentStep);
          }
          
          getSuperStepList(currentStep.getID() ,superStepList, includeAutoTask);
        }
      }
    } catch (ApplicationException ex) {
      log.error(ex);
      throw ex;
    }
    return(superStepList);
  }
  
  /**
   * Gets a list of child (and its childs) steps that is directly under this step
   *
   * @param stepID The current step ID
   * @param childStepList The List of child steps, initially empty (new ArrayList)
   * @return List of all the non-auto child step
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   */
  public List getChildStepList(Integer stepID, List childStepList) throws ApplicationException {
    MtmWorkflowStepWorkflowStepDAObject stepStepDAO = new MtmWorkflowStepWorkflowStepDAObject(sessionCon, dbConn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.sessionCon, this.dbConn);
    try {
      List tempstepList = stepStepDAO.getListByParentStepID(stepID);
      for(int i=0;i<tempstepList.size();i++){
        MtmWorkflowStepWorkflowStep mtmStepStep = (MtmWorkflowStepWorkflowStep)tempstepList.get(i);
        // selected step can not auto task,
        if (!GlobalConstant.TRUE.equals(mtmStepStep.getLoopBack())) {
          WorkflowStep currentStep = (WorkflowStep)stepDAO.getObjectByID(mtmStepStep.getChildStepID());
          if (!WorkflowStep.ACTION_TYPE_SYSTEM_AUTO.equals(currentStep.getActionType()) && Utility.isEmpty(currentStep.getActionID())) {
            childStepList.add(currentStep);
          }
          getChildStepList(currentStep.getID() ,childStepList);
        }
      }
    } catch (ApplicationException ex) {
      log.error(ex);
      throw ex;
    }
    return(childStepList);
  }
  
  /**
   * Gets a List of parent steps name as used for assign owners recursively
   *
   * @param parentStepID The current step ID
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowStep
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  public List getSuperStepNameListByWorkflowStepID(Integer parentStepID) throws ApplicationException{
    WorkflowStepDAObject workflowStepDAO = new WorkflowStepDAObject(this.sessionCon, this.dbConn); 
    List workflowStepList = new ArrayList();
    workflowStepList = this.getSuperStepList(parentStepID, workflowStepList);
    WorkflowStep parentStep = (WorkflowStep)workflowStepDAO.getObjectByID(parentStepID);
    List workflowStepNameList = new ArrayList();
    
    if (!Utility.isEmpty(parentStep) && !WorkflowStep.ACTION_TYPE_SUBMIT.equals(parentStep.getActionType())) {
      String[] aOption = new String[2];
      //For Previous Action Taker 
      aOption[1] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.n_step_action_taker", parentStep.getStepSeq() + ". " + parentStep.getStepName());
      aOption[0] = MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + parentStep.getID().toString();
      workflowStepNameList.add(aOption); 
      
      //For Previous Action Taker's Report To
      aOption = new String[2];
      aOption[1] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.step_n_action_taker_report_to", parentStep.getStepSeq() + ". " + parentStep.getStepName()); 
      aOption[0] = MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + parentStep.getID().toString();
      workflowStepNameList.add(aOption);
    } 
    if(!Utility.isEmpty(workflowStepList) ){
      for(int i = 0;i < workflowStepList.size();i++){
        WorkflowStep workflowStep = (WorkflowStep)workflowStepList.get(i);
        if ( !WorkflowStep.ACTION_TYPE_SUBMIT.equals(workflowStep.getActionType()) ) {
          String[] aOption = new String[2];
          //For Previous Action Taker
          aOption[1] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.n_step_action_taker", workflowStep.getStepSeq() + ". " + workflowStep.getStepName());                
          aOption[0] = MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER + workflowStep.getID().toString();
          workflowStepNameList.add(aOption);
          
          //For Previous Action Taker's Report To
          aOption = new String[2];
          aOption[1] = MessageResourcesFactory.getMessage(this.sessionCon.getSessionLocale(), "workflow.label.step_n_action_taker_report_to", workflowStep.getStepSeq() + ". " + workflowStep.getStepName()); 
          aOption[0] = MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER + workflowStep.getID().toString();
          workflowStepNameList.add(aOption);
        }
      }
    }
    return workflowStepNameList;
  }
  
  /** 
   * Gets a list of interrupted progress for given workflow track and workflow step
   * 
   * @param trackID The workflow track ID
   * @param stepID The workflow step ID
   * @return list of WorkflowProgress object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public List getInterruptedProgressList(Integer trackID, Integer stepID) throws ApplicationException {
    WorkflowProgressDAObject workflowProgressDAO = new WorkflowProgressDAObject(this.sessionCon, this.dbConn);
    WorkflowStepDAObject workflowStepDAO = new WorkflowStepDAObject(this.sessionCon, this.dbConn);
    List workflowProgressList = new ArrayList();
    List workflowStepList = new ArrayList();
    List workflowStepIDList = new ArrayList();
    boolean isCompleteWF = false;
    WorkflowProgress workflowProgress = null;
    if (!Utility.isEmpty(stepID)) {
      workflowStepIDList.add(stepID);
      this.getChildStepList(stepID, workflowStepList);
    } else {
      List progressList = workflowProgressDAO.getListByTrackID(trackID);
      if (!Utility.isEmpty(progressList)) {
        WorkflowProgress tmpWorkflowProgress = (WorkflowProgress)progressList.get(0);       
        if(GlobalConstant.TRUE.equals(tmpWorkflowProgress.getCompleteFlag())){
          isCompleteWF = true;
          workflowProgress = (WorkflowProgress)progressList.get(progressList.size()-1);
        }else{
          workflowProgress = (WorkflowProgress)progressList.get(0);
        }
        WorkflowStep currentStep = (WorkflowStep)workflowStepDAO.getObjectByID(workflowProgress.getWorkflowStepID());
        workflowStepList = workflowStepDAO.getListByWorkflowRecordID(currentStep.getWorkflowRecordID());
      }
    }
    for (int i = 0; !Utility.isEmpty(workflowStepList) && i < workflowStepList.size(); i++) {
      WorkflowStep workflowStep = (WorkflowStep)workflowStepList.get(i);
      workflowStepIDList.add(workflowStep.getID());
    }
    if(isCompleteWF && !Utility.isEmpty(workflowProgress)){
      workflowProgressList.add(workflowProgress);
    }else{
      workflowProgressList = workflowProgressDAO.getListByTrackIDStepIDList(trackID, workflowStepIDList);
    }
    log.debug("The workflowProgressList is ::" + workflowProgressList.size());
    return workflowProgressList;
  }
  /**
   * Gets a list of locked progress for given workflow track and workflow step
   * 
   * @param trackID The workflow track ID
   * @param stepID The workflow step ID
   * @return list of WorkflowProgress object
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.WorkflowProgress
   */
  public List getLockedProgressList(Integer trackID, Integer stepID) throws ApplicationException {
    WorkflowProgressDAObject workflowProgressDAO = new WorkflowProgressDAObject(this.sessionCon, this.dbConn);
    WorkflowStepDAObject workflowStepDAO = new WorkflowStepDAObject(this.sessionCon, this.dbConn);
    List workflowProgressList = new ArrayList();
    List workflowStepList = new ArrayList();
    List workflowStepIDList = new ArrayList();
    if (!Utility.isEmpty(stepID)) {
      workflowStepIDList.add(stepID);
      this.getChildStepList(stepID, workflowStepList);
    } else {
      List progressList = workflowProgressDAO.getListByTrackID(trackID);
      if (!Utility.isEmpty(progressList)) {
        WorkflowStep currentStep = (WorkflowStep)workflowStepDAO.getObjectByID(((WorkflowProgress)progressList.get(0)).getWorkflowStepID());
        workflowStepList = workflowStepDAO.getListByWorkflowRecordID(currentStep.getWorkflowRecordID());
      }
    }
    for (int i = 0; !Utility.isEmpty(workflowStepList) && i < workflowStepList.size(); i++) {
      WorkflowStep workflowStep = (WorkflowStep)workflowStepList.get(i);
      workflowStepIDList.add(workflowStep.getID());
    }
    workflowProgressList = workflowProgressDAO.getLockedListByTrackIDStepIDList(trackID, workflowStepIDList);
    return workflowProgressList;
  }
  
  /**
   * get bind form item value
   * 
   * @param stepID The workflow step ID
   * @return string a text contain the permission info about given step between related form,
   *                a "" text will be return if there are any info about them.
   * @throws ApplicationException
   */
  private String getBindFormItemValue(Integer stepID)throws ApplicationException {
    MtmWfStepFormRecordDAObject stepFormRecordDAO = new MtmWfStepFormRecordDAObject(this.sessionCon, this.dbConn);
    List stepFormList = stepFormRecordDAO.getListByWorkflowStepID(stepID);
    String bindFormItemValue = "";
    for (int i=0; i<stepFormList.size(); i++) {
      MtmWfStepFormRecord stepFormRecord = (MtmWfStepFormRecord)stepFormList.get(i); 
      if (i == 0) {bindFormItemValue += "|";}
      if(GlobalConstant.TRUE.equals(stepFormRecord.getMandatory())){
        bindFormItemValue += "M";
      } else {
        bindFormItemValue += stepFormRecord.getPermission();
      }
      
      if(!Utility.isEmpty(stepFormRecord.getFormElementID())){
        bindFormItemValue += "E" + stepFormRecord.getFormElementID().toString();
        
      } else if(!Utility.isEmpty(stepFormRecord.getFormSectionID())){
        bindFormItemValue += "S" + stepFormRecord.getFormSectionID().toString();
        
      } else if(!Utility.isEmpty(stepFormRecord.getFormPageID())){
        bindFormItemValue += "P" + stepFormRecord.getFormPageID().toString();
        
      } else if(!Utility.isEmpty(stepFormRecord.getFormRecordID())) {				
        bindFormItemValue += "F" + stepFormRecord.getFormRecordID().toString();
      }
      bindFormItemValue += "|";
    }
    // bindFormItemValue += "|";
    return bindFormItemValue;
  }
  //added by nancy
  /**
   * Gets workflow auto task's parameter names(and parameter values)
   * 
   * @param stepID The workflow step ID
   * @param actionType The action type
   * @return String The string eg.(parameter name1:parameter value1|parameter name2:parameter value2|.....)
   * @throws ApplicationException
   */
  public String getStringForParameter(Integer stepID,String actionType) throws ApplicationException{
    List templist=new ArrayList();
    StringBuffer tempstr=new StringBuffer();
    WorkflowActionDAObject actionDAO = new WorkflowActionDAObject(sessionCon, dbConn);
    
    if(!Utility.isEmpty(actionType)&&!(actionType.substring(0,1)).equals(WorkflowStep.ACTION_TYPE_SYSTEM_AUTO)){
      return tempstr.toString();	
    }
    
    if(!Utility.isEmpty(actionType)){//get values from class
      WorkflowAction wfAction = (WorkflowAction)actionDAO.getObjectByID(Integer.valueOf(actionType.substring(1)));
      WorkflowProcessor processor = AutomaticTaskFactory.getInstance(wfAction);//mod by greatwall for AutomaticTask
      String[] temp=processor.getParameterNames();
      for(int i=0;i<temp.length;i++){
        tempstr.append(temp[i]+": |");
      }
      //stepForm.setParameterListValue(tempstr.toString());
    }
    else{//get values from DB
      WorkflowStepParameterValueDAObject parameterDAO=new WorkflowStepParameterValueDAObject(sessionCon, dbConn);
      //  	
      templist=parameterDAO.getListByStepID(stepID);
      if(!Utility.isEmpty(templist)){
        WorkflowStepParameterValue tt=null;
        for (int i = 0; i < templist.size(); i++) {
          tt = (WorkflowStepParameterValue) templist.get(i);
          if (!PARAMVALUE_AUTOTASK.equals(tt.getParameterType().trim())) {
            tempstr.append(tt.getParameterName() + ":" + tt.getParameterValue() + "|");
          }
        }
      }
    }
    return tempstr.toString();
  }
  
  /**
   * get workflow stage ID by workflow step ID
   * @param workflowStepID
   * @return Integer  workflow stage ID
   * @throws ApplicationException
   */  
  private Integer getWorkflowStageByWorkflowStepID(Integer workflowStepID) throws ApplicationException {
    Integer workflowStage = new Integer(-1);
    WorkflowStageDAObject stageDAO = new WorkflowStageDAObject(this.sessionCon, this.dbConn);
    WorkflowStage stage = (WorkflowStage) stageDAO.getObjectByWorkflowStepID(workflowStepID);
    if (!Utility.isEmpty(stage)) {
      workflowStage = stage.getID();
    }
    return workflowStage;
  }
  /**
   * falcon_add
   * 
   * @param currentWorkflowProgressID
   * @return  list of workflowProgress object
   */
  public List getNonAutomaticParent(Integer currentWorkflowProgressID) {
	WorkflowProgressDAObject  wfProgressDAO = new WorkflowProgressDAObject(this.sessionCon, this.dbConn);
    MtmWfProgressWfProgressDAObject mtmWfProgressDAO = new MtmWfProgressWfProgressDAObject(this.sessionCon, this.dbConn);  
    try {
      List parentWfProgressList = mtmWfProgressDAO.getListByChildProgressID(currentWorkflowProgressID);   
      for (int i = 0; i < parentWfProgressList.size(); i++) {
    	  MtmWfProgressWfProgress mtmWfProgress = (MtmWfProgressWfProgress) parentWfProgressList.get(i);
          WorkflowProgress parentWfProgress = (WorkflowProgress)wfProgressDAO.getObjectByID(mtmWfProgress.getParentProgressID());
          if (workflowProgressList.contains(parentWfProgress)) {
              continue;
            }
          workflowProgressList.add(parentWfProgress);
          getNonAutomaticParent(parentWfProgress.getID());
      }
    } catch (ApplicationException ex) {
      log.error(ex);
    }
    return workflowProgressList;
  }
  
  //TC.ADD START FOR WORKFLOW STEP CHECK
  /**
   * check if subSeq contains currentStep
   * @param parentStepID
   * @param currentStepID
   * @return
   * @throws ApplicationException
   */
  public boolean checkIfSubSequentStepsContainedCurrentStep(Integer parentStepID,Integer currentStepID) throws ApplicationException{
    MtmWorkflowStepWorkflowStepDAObject mtmStepStepDao = new MtmWorkflowStepWorkflowStepDAObject(this.sessionCon,this.dbConn);
    if(parentStepID.equals(currentStepID)) {
      return true;
    }
    List mtmStepStepList = mtmStepStepDao.getListByParentStepID(parentStepID);
    for(int i=0;i<mtmStepStepList.size();i++){
      MtmWorkflowStepWorkflowStep stepStep = (MtmWorkflowStepWorkflowStep)mtmStepStepList.get(i);
      Integer tempChildID = stepStep.getChildStepID();
      if(tempChildID.equals(currentStepID)) {
        return true;
      }
    }
    for(int y=0;y<mtmStepStepList.size();y++){
      MtmWorkflowStepWorkflowStep stepStep = (MtmWorkflowStepWorkflowStep)mtmStepStepList.get(y);
      Integer tempChildID = stepStep.getChildStepID();
      boolean result = checkIfSubSequentStepsContainedCurrentStep(tempChildID,currentStepID);
      if(result) {
        return result;
      }
    }
    return false;
  }
  
  public boolean checkIfOneBranchContainsAnyCurrentSteps(Integer parentStep,Integer[] currentSteps) throws ApplicationException{
    if(Utility.isEmpty(currentSteps)){
      throw new ApplicationException("Array currentSteps is Null");
    }
    for(int i=0;i<currentSteps.length;i++){
      if(currentSteps[i].equals(parentStep)) {
        continue;
      }
      //if subSteps of parentStep don't contains one of array return false
      if(!checkIfSubSequentStepsContainedCurrentStep(parentStep,currentSteps[i])){
        return false;
      }
    }
    return true;
  }
  
  public boolean checkIfOneBranchOfParrallelContainsCurrentSteps(Integer currentStep,Integer[] currentSteps) throws ApplicationException{
    boolean flag = true;
    //contains the parallel Step ID have found
    
    List parallelList = new ArrayList();
    
    while(flag){
      Integer tmpStepID = null;
      
      if(parallelList.size()>0){
        tmpStepID = (Integer)parallelList.get(parallelList.size()-1);
      }else{
        tmpStepID = currentStep; 
      }
      
      //get the near parent parallel's current branch stepID which subSteps contans tmpStep
      Integer stepID = getOneBranchOfParrallelStep(tmpStepID,parallelList,null);

      //if did not find the branch of parrallel Step than stop and throw Exception;
      if(Utility.isEmpty(stepID)){
        flag = false;
        throw new ApplicationException("can not find the parallel Step!");
      }
      
      for(int i=0;i<currentSteps.length;i++){
        
        // if this branch contains currentStep and any element of array than return true
        if(checkIfOneBranchContainsAnyCurrentSteps(stepID,new Integer[]{currentStep,currentSteps[i]})){
          return true;
        }
      }
      //if nearest branch of parallel did not contains any element of array than return false
      return false;
      
    }
    return false;
  }
  
  public Integer getOneBranchOfParrallelStep(Integer currentStep,List parallelStepList,MtmWorkflowStepWorkflowStepDAObject mtmStepStepDao) throws ApplicationException{
    if(Utility.isEmpty(mtmStepStepDao)){
      mtmStepStepDao = new MtmWorkflowStepWorkflowStepDAObject(this.sessionCon,this.dbConn);
    }
    
    List stepStepList = mtmStepStepDao.getListByChildStepIDAndLoopBack(currentStep, "N");
    
    // currentStep is the start workflow Step
    if(stepStepList.size()<=0){
      return null;
    }
    
    MtmWorkflowStepWorkflowStep stepStep = null;
    for(int i=0;i<stepStepList.size();i++){
      stepStep = (MtmWorkflowStepWorkflowStep)stepStepList.get(i);
      
      if(isParrallelStep(stepStep.getParentStepID(),stepStep.getParentType(),mtmStepStepDao)){
        //is ParrallelStep than return this childStep
        parallelStepList.add(stepStep.getParentStepID());
        return stepStep.getChildStepID();
      }
    }
    //none of above is parallel Step
    
    for(int j=0;j<stepStepList.size();j++){
      stepStep = (MtmWorkflowStepWorkflowStep)stepStepList.get(j);
      Integer result = getOneBranchOfParrallelStep(stepStep.getParentStepID(),parallelStepList,mtmStepStepDao);
      //get the current branch of parallel Step
      if(!Utility.isEmpty(result)){
        return result;
      }
    }
    return null;
  }
  
  private boolean isParrallelStep(Integer parentStepID,String parentType,MtmWorkflowStepWorkflowStepDAObject stepStepDAO) throws ApplicationException{
    List stepStepID=stepStepDAO.getListByParentStepIDAndParentType(parentStepID, parentType); 
    //if one parentStep have more one child Step with same parentType than it is parallel Step
    if(stepStepID.size()>1){
      return true;
    }
    return false;
  }
  
  public List retrieveWorkflowStepArray(Integer workflowStepID,String parentType) throws ApplicationException {
    List parentStepList = new ArrayList();
    try{
      Locale locale = this.sessionCon.getSessionLocale();
      WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.sessionCon,this.dbConn);
      WorkflowStep workflowStep = (WorkflowStep)stepDAO.getObjectByID(workflowStepID);

        WorkflowStep tmpStep = workflowStep;
        String actionType = tmpStep.getActionType();

        if (WorkflowStep.ACTION_TYPE_SUBMIT.equals(actionType)) {
          String[] aOption = new String[2];
          aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_S") + "]";
          aOption[1] = WorkflowStep.PARENT_TYPE_SINGLE + "-" + tmpStep.getID();
          parentStepList.add(aOption);

        } else if (WorkflowStep.ACTION_TYPE_APPROVAL.equals(actionType)) {
          if(Utility.isEmpty(parentType)||WorkflowStep.PARENT_TYPE_APPROVED.equals(parentType)){
            String[] aOption = new String[2];
            aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_A") + "]";
            aOption[1] = WorkflowStep.PARENT_TYPE_APPROVED + "-" + tmpStep.getID();
            parentStepList.add(aOption);
          }
          if(Utility.isEmpty(parentType)||WorkflowStep.PARENT_TYPE_REJECTED.equals(parentType)){
            String[]aOption = new String[2];
            aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_R") + "]";
            aOption[1] = WorkflowStep.PARENT_TYPE_REJECTED + "-" + tmpStep.getID();
            parentStepList.add(aOption);
          }
        } else if (WorkflowStep.ACTION_TYPE_BOOLEAN.equals(actionType)) {
          if(Utility.isEmpty(parentType)||WorkflowStep.PARENT_TYPE_YES.equals(parentType)){
            String[] aOption = new String[2];
            aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_T") + "]";
            aOption[1] = WorkflowStep.PARENT_TYPE_YES + "-" + tmpStep.getID();
            parentStepList.add(aOption);
          }
          if(Utility.isEmpty(parentType)||WorkflowStep.PARENT_TYPE_NO.equals(parentType)){
            String[] aOption = new String[2];
            aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_F") + "]";
            aOption[1] = WorkflowStep.PARENT_TYPE_NO + "-" + tmpStep.getID();
            parentStepList.add(aOption);
          }

        } else if (WorkflowStep.ACTION_TYPE_FORM_DRIVEN.equals(actionType)) {
         // if(!Utility.isEmpty(tmpStep.getRouteListValue()) ){
         //   String[] routeArr = TextUtility.splitString(tmpStep.getRouteListValue(),"|");
          WorkflowStepFormEquatDAObject formEquatDAO = new WorkflowStepFormEquatDAObject(this.sessionCon, this.dbConn);
          List routeList = formEquatDAO.getListByWorkflowStepID(tmpStep.getID());
          for(int j=0; j<routeList.size(); j++){
            WorkflowStepFormEquat route = (WorkflowStepFormEquat)routeList.get(j);  
            if(Utility.isEmpty(parentType)||(WorkflowStep.PARENT_TYPE_SINGLE + j).equals(parentType)){
                String[] aOption = new String[2];
                aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + route.getRouteName() + "]";//MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_U")
                aOption[1] = WorkflowStep.PARENT_TYPE_SINGLE + j + "-" + tmpStep.getID();
                parentStepList.add(aOption);
              }
            }
          //}
        } else if (WorkflowStep.ACTION_TYPE_USER_DEFINED_TASK.equals(actionType)) {
          //if(!Utility.isEmpty(tmpStep.getRouteListValue()) ){
          //  String[] routeArr = TextUtility.splitString(tmpStep.getRouteListValue(),"|");
          //  for(int j=0; j<routeArr.length; j++){
          WorkflowStepRouteDAObject wfStepRouteDAO = new WorkflowStepRouteDAObject(this.sessionCon,this.dbConn);
          List routeList = wfStepRouteDAO.getListByWorkflowStepID(tmpStep.getID());
          for(int j=0; j<routeList.size(); j++){
             WorkflowStepRoute route = (WorkflowStepRoute)routeList.get(j);
              if(Utility.isEmpty(parentType)||(WorkflowStep.PARENT_TYPE_SINGLE + j).equals(parentType)){
                String[] aOption = new String[2];
                aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + route.getRouteName() + "]";//MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_U")
                aOption[1] = WorkflowStep.PARENT_TYPE_SINGLE + j + "-" + tmpStep.getID();
                parentStepList.add(aOption);
              }
            }
         // }

        } else if (WorkflowStep.ACTION_TYPE_TASK_TO_DO.equals(actionType)) {
          String[] aOption = new String[2];
          aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_G") + "]";
          aOption[1] = WorkflowStep.PARENT_TYPE_SINGLE + "-" + tmpStep.getID();
          parentStepList.add(aOption);

        } else if (WorkflowStep.ACTION_TYPE_SYSTEM_AUTO.equals(actionType)) {

          /***************************************************
           * TODO: handle different type of automatic task
           ***************************************************/
          WorkflowAction action = getWorkflowActionByActionID(tmpStep.getActionID());
          WorkflowProcessor processor = AutomaticTaskFactory.getInstance(action);//Edit by TC for automaticTask Hotdeploy

          if (processor.getNumOfRoutine() == 1) {
            String[] aOption = new String[2];
            aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, "workflow.label.step_status_G") + "]";
            aOption[1] = "S" + "-" + tmpStep.getID();
            parentStepList.add(aOption);
          } else {
            for(int j=0; j<processor.getNumOfRoutine(); j++) {
              if(Utility.isEmpty(parentType)||("S" + j).equals(parentType)){
                String[] aOption = new String[2];
                aOption[0] = tmpStep.getStepSeq() + ". " + tmpStep.getStepName() + "[" + MessageResourcesFactory.getMessage(locale, processor.getLabelString(j)) + "]";
                aOption[1] = "S" + j + "-" + tmpStep.getID();
                parentStepList.add(aOption);
              }
            }
          }
        } else if (WorkflowStep.ACTION_TYPE_END.equals(actionType)) {
          //SUBJECT TO CHANGE: now do nothing for the end node case, that means no step can be add after end step
        } else {
          throw new ApplicationException(WorkflowErrorConstant.UNKNOWN_WORKFLOW_ACTION_TYPE);
        }
    
      return parentStepList;
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.COMMON_UNKNOWN_DAO, e);
    } 
  }
  
  public List retrieveWorkflowStepToEndStepArray(Integer workflowStepID) throws ApplicationException{

    List result = new ArrayList();
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.sessionCon,this.dbConn);
    MtmWorkflowStepWorkflowStepDAObject stepStepDAO = new MtmWorkflowStepWorkflowStepDAObject(this.sessionCon,this.dbConn);
    
    WorkflowStep workflowStep = (WorkflowStep)stepDAO.getObjectByID(workflowStepID);
    WorkflowStep endStep = (WorkflowStep)stepDAO.getEndStepByWorkflowRecordID(workflowStep.getWorkflowRecordID());
    
    //get the end List
    List endList = stepStepDAO.getListByChildStepID(endStep.getID());
    
    for(int i=0;i<endList.size();i++){
      MtmWorkflowStepWorkflowStep tmpStepStep = (MtmWorkflowStepWorkflowStep)endList.get(i);
      
      //check if tmpStepStep.parentID in the subTree of workflowStepID
      if(checkIfSubSequentStepsContainedCurrentStep(workflowStepID,tmpStepStep.getParentStepID())){
        result.addAll(retrieveWorkflowStepArray(tmpStepStep.getParentStepID(),tmpStepStep.getParentType()));
      }
    }//
    
    return result;
  }
  //TC.ADD END
}